{
 "cells": [
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "# Tutorial 2: Running Aimsun Simulations\n",
    "\n",
    "This tutorial walks through the process of running non-RL traffic simulations in Flow with Aimsun. This tutorial is a near direct copy of the `tutorial01_sumo.ipynb` since some modifications to describe Aimsun-specific features. This tutorial, however, is self-sufficient for readers who have not gone through the previous tutorial.\n",
    "\n",
    "*If, instead of running a Flow-created network in Aimsun, you wish to run an already existing Aimsun template using Flow, please refer to the tutorial on network templates (`tutorial08_network_templates.ipynb`).*\n",
    "\n",
    "Simulations of this form act as non-autonomous baselines and depict the behavior of human dynamics on a network. Similar simulations may also be used to evaluate the performance of hand-designed controllers on a network. This tutorial focuses primarily on the former use case, while an example of the latter may be found in `tutorial10_controllers.ipynb`.\n",
    "\n",
    "In this tutorial, we simulate an initially perturbed single lane ring road. We witness in simulation that as time advances, the initial perturbations do not dissipate, but instead propagate and expand until vehicles are forced to periodically stop and accelerate. For more information on this behavior, we refer the reader to the following article [1].\n",
    "\n",
    "## 1. Components of a Simulation\n",
    "All simulations, both in the presence and absence of RL, require two components: a *network*, and an *environment*. Networks describe the features of the transportation network used in simulation. This includes the positions and properties of nodes and edges constituting the lanes and junctions, as well as properties of the vehicles, traffic lights, inflows, etc. in the network. Environments, on the other hand, initialize, reset, and advance simulations, and act the primary interface between the reinforcement learning algorithm and the network. Moreover, custom environments may be used to modify the dynamical features of an network.\n",
    "\n",
    "## 2. Setting up a Network\n",
    "Flow contains a plethora of pre-designed networks used to replicate highways, intersections, and merges in both closed and open settings. All these networks are located in flow/networks. In order to recreate a ring road network, we begin by importing the network `RingNetwork`."
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "from flow.networks.ring import RingNetwork"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "This network, as well as all other network in Flow, is parametrized by the following arguments: \n",
    "* name\n",
    "* vehicles\n",
    "* net_params\n",
    "* initial_config\n",
    "* traffic_lights\n",
    "\n",
    "These parameters allow a single network to be recycled for a multitude of different network settings. For example, `RingNetwork` may be used to create ring roads of variable length with a variable number of lanes and vehicles.\n",
    "\n",
    "### 2.1 Name\n",
    "The `name` argument is a string variable depicting the name of the network. This has no effect on the type of network created."
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "name = \"ring_example\""
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "### 2.2 VehicleParams\n",
    "The `VehicleParams` class stores state information on all vehicles in the network. This class is used to identify the dynamical behavior of a vehicle and whether it is controlled by a reinforcement learning agent. Morover, information pertaining to the observations and reward function can be collected from various get methods within this class.\n",
    "\n",
    "The initial configuration of this class describes the number of vehicles in the network at the start of every simulation, as well as the properties of these vehicles. We begin by creating an empty `VehicleParams` object."
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "from flow.core.params import VehicleParams\n",
    "\n",
    "vehicles = VehicleParams()"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "Once this object is created, vehicles may be introduced using the `add` method. This method specifies the types and quantities of vehicles at the start of a simulation rollout. For a description of the various arguements associated with the `add` method, we refer the reader to the following documentation (reference readthedocs).\n",
    "\n",
    "When adding vehicles, their dynamical behaviors may be specified either by the simulator (default), or by user-generated models. For longitudinal (acceleration) dynamics, several prominent car-following models are implemented in Flow. For this example, the acceleration behavior of all vehicles will be defined by the Intelligent Driver Model (IDM) [2]."
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "from flow.controllers.car_following_models import IDMController"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "While Flow does support the use of custom routers is sumo, this feature is not currently available when using Aimsun. Vehciles, instead, will continuously route to the next available edge. Accordingly, we will not specify a routing controller.\n",
    "\n",
    "Finally, we add 22 vehicles of type \"human\" with the above acceleration and routing behavior into the `Vehicles` class."
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "vehicles.add(\"human\",\n",
    "             acceleration_controller=(IDMController, {}),\n",
    "             num_vehicles=22)"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "### 2.3 NetParams\n",
    "\n",
    "`NetParams` are network-specific parameters used to define the shape and properties of a network. Unlike most other parameters, `NetParams` may vary drastically depending on the specific network configuration, and accordingly most of its parameters are stored in `additional_params`. In order to determine which `additional_params` variables may be needed for a specific network, we refer to the `ADDITIONAL_NET_PARAMS` variable located in the network file."
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "from flow.networks.ring import ADDITIONAL_NET_PARAMS\n",
    "\n",
    "print(ADDITIONAL_NET_PARAMS)"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "Importing the `ADDITIONAL_NET_PARAMS` dict from the ring road network, we see that the required parameters are:\n",
    "\n",
    "* **length**: length of the ring road\n",
    "* **lanes**: number of lanes\n",
    "* **speed**: speed limit for all edges\n",
    "* **resolution**: resolution of the curves on the ring. Setting this value to 1 converts the ring to a diamond.\n",
    "\n",
    "\n",
    "At times, other inputs may be needed from `NetParams` to recreate proper network features/behavior. These requirements can be founded in the network's documentation. For the ring road, no attributes are needed aside from the `additional_params` terms. Furthermore, for this tutorial, we use the network's default parameters when creating the `NetParams` object."
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "from flow.core.params import NetParams\n",
    "\n",
    "net_params = NetParams(additional_params=ADDITIONAL_NET_PARAMS)"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "### 2.4 InitialConfig\n",
    "\n",
    "`InitialConfig` specifies parameters that affect the positioning of vehicle in the network at the start of a simulation. These parameters can be used to limit the edges and number of lanes vehicles originally occupy, and provide a means of adding randomness to the starting positions of vehicles. In order to introduce a small initial disturbance to the system of vehicles in the network, we set the `perturbation` term in `InitialConfig` to 1m."
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "from flow.core.params import InitialConfig\n",
    "\n",
    "initial_config = InitialConfig(spacing=\"uniform\", perturbation=1)"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "### 2.5 TrafficLightParams\n",
    "\n",
    "`TrafficLightParams` are used to desribe the positions and types of traffic lights in the network. These inputs are outside the scope of this tutorial, and instead are covered in `tutorial10_traffic_lights.ipynb`. For our example, we create an empty `TrafficLightParams` object, thereby ensuring that none are placed on any nodes."
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "from flow.core.params import TrafficLightParams\n",
    "\n",
    "traffic_lights = TrafficLightParams()"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "### 2.6 Aimsun Template\n",
    "\n",
    "While the aimsun template is not a parameter within the network class, it is a significant component of the network that will be generated. The default template in Flow is located in:\n",
    "\n",
    "```\n",
    "/path/to/flow/flow/utils/aimsun/Aimsun_Flow.ang\n",
    "```\n",
    "\n",
    "This template is further modified to create the network we will see towards the end of this tutorial.\n",
    "\n",
    "If you were to double click on this template, a window similar to the one below will appear. From here, you can modify any network or simulation parameters you would like that are not currently available within Flow. Being that the incorporation of Aimsun into Flow is still in its early stages, not many features are currently available, so modifying this template may be of use at times.\n",
    "\n",
    "<img src=\"img/aimsun_template.png\" width=\"1000\">"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "## 3. Setting up an Environment\n",
    "\n",
    "Several envionrments in Flow exist to train autonomous agents of different forms (e.g. autonomous vehicles, traffic lights) to perform a variety of different tasks. These environments are often network or task specific; however, some can be deployed on an ambiguous set of networks as well. One such environment, `AccelEnv`, may be used to train a variable number of vehicles in a fully observable network with a *static* number of vehicles."
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "from flow.envs.ring.accel import AccelEnv"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "Although we will not be training any autonomous agents in this tutorial, the use of an environment allows us to view the cumulative reward simulation rollouts receive in the absence of autonomy.\n",
    "\n",
    "Envrionments in Flow are parametrized by several components, including the following attributes:\n",
    "* `sim_params`\n",
    "* `env_params`\n",
    "* `network`\n",
    "* `net_params`\n",
    "* `initial_config`\n",
    "* `network`\n",
    "* `simulator`\n",
    "\n",
    "where `sim_params`, `env_params`, and `network` the are primary parameters of an environment. For the full list of attributes, please check `class Env` in `flow/envs/base.py`.\n",
    "\n",
    "Aimsun envrionments in Flow are parametrized by three components:\n",
    "* `AimsunParams`\n",
    "* `EnvParams`\n",
    "* `Network`\n",
    "\n",
    "### 3.1 AimsunParams\n",
    "`AimsunParams` specifies simulation-specific variables. These variables include the length a simulation step (in seconds) and whether to render the GUI when running the experiment. For this example, we set `render` within the simulation params to be True in order for vehicles to appear on the GUI during the simulation."
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "from flow.core.params import AimsunParams\n",
    "\n",
    "sim_params = AimsunParams(render=True)"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "Note that if `render` were set to False the GUI would still turn on, but no vehicles or traffic lights would be rendered. This significantly improves runtimes. It is also worth mentioning that, being that the incorporation of Aimsun into Flow is still in beta stage, only the `render`, `sim_step`, and `emission_path` parameters within `AimsunParams` currently function. If you would like to update the simulation step, for instance, this must be done directly from the default template (see section 2.6).\n",
    "\n",
    "### 3.2 EnvParams\n",
    "\n",
    "`EnvParams` specify environment and experiment-specific parameters that either affect the training process or the dynamics of various components within the network. Much like `NetParams`, the attributes associated with this parameter are mostly environment specific, and can be found in the environment's `ADDITIONAL_ENV_PARAMS` dictionary."
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "from flow.envs.ring.accel import ADDITIONAL_ENV_PARAMS\n",
    "\n",
    "print(ADDITIONAL_ENV_PARAMS)"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "Importing the `ADDITIONAL_ENV_PARAMS` variable, we see that it consists of only one entry, \"target_velocity\", which is used when computing the reward function associated with the environment. We use this default value when generating the `EnvParams` object."
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "from flow.core.params import EnvParams\n",
    "\n",
    "env_params = EnvParams(additional_params=ADDITIONAL_ENV_PARAMS)"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "## 4. Setting up and Running the Experiment\n",
    "\n",
    "Once the inputs to the network and environment classes are ready, we are ready to set up a `Experiment` object."
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "from flow.core.experiment import Experiment"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "These objects may be used to simulate rollouts in the absence of reinforcement learning agents, as well as acquire behaviors and rewards that may be used as a baseline with which to compare the performance of the learning agent. In this case, we choose to run our experiment for one rollout consisting of 3000 steps (300 s). Note that, unlike in tutorial 1, here we use the Aimsun simulator when running the ring road experiment by setting the `simulator` attribute of the environment as \"aimun\". The default simulator for all environments in Flow is sumo.\n",
    "\n",
    "In order to start the simulation, run the below cell. A new Aimsun GUI will open and prompt you to save the file. Save this file anywhere (so long as you do not overwrite the default template), and once you have done so, the simulation will execute."
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "flow_params = dict(\n",
    "    exp_tag='test_network',\n",
    "    env_name=AccelEnv,\n",
    "    network=RingNetwork,\n",
    "    simulator='aimsun',\n",
    "    sim=sim_params,\n",
    "    env=env_params,\n",
    "    net=net_params,\n",
    "    veh=vehicles,\n",
    "    initial=initial_config,\n",
    "    tls=traffic_lights\n",
    ")\n",
    "\n",
    "# number of time steps\n",
    "flow_params['env'].horizon = 3000\n",
    "exp = Experiment(flow_params)\n",
    "\n",
    "# run the Aimsun simulation\n",
    "_ = exp.run(1)"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "If you encounter an error of the form `ImportError: No module named flow` within Aimsun, make sure that you have correctly setup the `aimsun_flow` environment ([installation instructions](https://flow.readthedocs.io/en/latest/flow_setup.html#installing-aimsun)) and that you are running this notebook inside the `flow` environment (for more information on this, see the [note in README.md](https://github.com/flow-project/flow/blob/master/tutorials/README.md#tutorials))."
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "## 5. Modifying the Simulation\n",
    "This tutorial has walked you through running a single lane ring road experiment in Flow. As we have mentioned before, these simulations are highly parametrizable. This allows us to try different representations of the task. For example, what happens if no initial perturbations are introduced to the system of homogenous human-driven vehicles?\n",
    "\n",
    "```\n",
    "initial_config = InitialConfig()\n",
    "```\n",
    "\n",
    "In addition, how does the task change in the presence of multiple lanes where vehicles can overtake one another?\n",
    "\n",
    "```\n",
    "net_params = NetParams(\n",
    "    additional_params={\n",
    "        'length': 230, \n",
    "        'lanes': 2, \n",
    "        'speed_limit': 30, \n",
    "        'resolution': 40\n",
    "    }\n",
    ")\n",
    "```\n",
    "\n",
    "Feel free to experiment with all these problems and more!\n",
    "\n",
    "## Bibliography\n",
    "[1] Sugiyama, Yuki, et al. \"Traffic jams without bottlenecks—experimental evidence for the physical mechanism of the formation of a jam.\" New journal of physics 10.3 (2008): 033001.\n",
    "\n",
    "[2] Treiber, Martin, Ansgar Hennecke, and Dirk Helbing. \"Congested traffic states in empirical observations and microscopic simulations.\" Physical review E 62.2 (2000): 1805."
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": []
  }
 ],
 "metadata": {
  "kernelspec": {
   "display_name": "Python 3",
   "language": "python",
   "name": "python3"
  },
  "language_info": {
   "codemirror_mode": {
    "name": "ipython",
    "version": 3
   },
   "file_extension": ".py",
   "mimetype": "text/x-python",
   "name": "python",
   "nbconvert_exporter": "python",
   "pygments_lexer": "ipython3",
   "version": "3.6.8"
  }
 },
 "nbformat": 4,
 "nbformat_minor": 2
}
